#include "tree_class.h"

void Tree::CreateTreeFromFile(string* newickString)
{
	string line;
	Node* root;
	
	//construct topology from syntax
	root = RecurseStringTopology(newickString);

	queue<Node*> nodeQueue;
	
	nodeQueue.push(root);

	while(nodeQueue.size() > 0)
	{
		Node* currentNode = nodeQueue.front();
		nodeQueue.pop();

		if(currentNode->leftNode != NULL)
			nodeQueue.push(currentNode->leftNode);
		if(currentNode->rightNode != NULL)
			nodeQueue.push(currentNode->rightNode);
		
		currentNode->currentIdx = nodeVector.size();
		nodeVector.push_back(currentNode);
	}

	length = nodeVector.size();
	phylogenyNodes = new Node*[nodeVector.size()];
	nodeVector[0]->parentIdx = 0;
	for(int i = 0; i < nodeVector.size(); i++)
	{
		if(nodeVector[i]->leftNode != NULL)
		{
			nodeVector[i]->leftIdx = nodeVector[i]->leftNode->currentIdx;
			nodeVector[i]->leftNode->parentIdx = i;
		}
		else
			nodeVector[i]->leftIdx = i;

		if(nodeVector[i]->rightNode != NULL)
		{
			nodeVector[i]->rightIdx = nodeVector[i]->rightNode->currentIdx;
			nodeVector[i]->rightNode->parentIdx = i;
		}
		else
			nodeVector[i]->rightIdx = i;
		
		phylogenyNodes[i] = nodeVector[i];
	}
}
Node* Tree::RecurseStringTopology(string* treeString)
{
	int open = 0;

	if(treeString->find(",") == string::npos)
		return new Node(treeString, NULL, NULL);
	else
	{
		for(int i = 0; i < (int)treeString->length(); i++)
		{
			switch((*treeString)[i])
			{
				case '(':
					open++;
					break;
				case ')':
					open--;
					break;
				case ',':
					if(open == 1)
						return new Node(NULL, RecurseStringTopology(&treeString->substr(1, i - 1)), RecurseStringTopology(&treeString->substr(i + 1, treeString->length() - (i+2))));
			}
		}
	}
	return NULL;
}

cNode* Tree::cudaNodeArray(int siteIdx){
	cNode* cudaNodes = new cNode[length];
	for(int n = 0; n < nodeVector.size(); n++){
		cudaNodes[n].left = phylogenyNodes[n]->leftIdx;
		cudaNodes[n].right = phylogenyNodes[n]->rightIdx;
		cudaNodes[n].parent = phylogenyNodes[n]->parentIdx;
		if(phylogenyNodes[n]->label != NULL){
			switch(sequences[*phylogenyNodes[n]->label][siteIdx]){
				case'G':
					cudaNodes[n].state = 0;
					break;
				case'A':
					cudaNodes[n].state = 1;
					break;
				case'T':
					cudaNodes[n].state = 2;
					break;
				case'C':
					cudaNodes[n].state = 3;
					break;
			}
		}
		else
			cudaNodes[n].state = 0;
		cudaNodes[n].recurse = 0;
	}
	return cudaNodes;
}